// 简单数据类型/栈: undefined,null,boolean,number,string,Symbol,BigInt
// 复杂数据类型引用数据类型 Object,Array,Func,Date,RegExp,Map

// Symbol 独一无二不可更改的数据类型
// BigInt 任意精度格式的整数

// 原始数据类型直接存储在栈（stack）中的简单数据段，占据空间⼩、⼤⼩固定，属于被频繁使⽤数据，所以放⼊栈中存储；

// 引⽤数据类型存储在堆（heap）中的对象，占据空间⼤、⼤⼩不固定。如果存储在栈中，将会影响
// 程序运⾏的性能；引⽤数据类型在栈中存储了指针，该指针指向堆中该实体的起始地址。当解释器
// 寻找引⽤值时，会⾸先检索其在栈中的地址，取得地址后从堆中获得实体

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // null 和 [] 会判定为object

        console.log(typeof 2); // number
        console.log(typeof true); // boolean
        console.log(typeof 'str'); // string
        console.log(typeof []); // object
        console.log(typeof function(){}); // function
        console.log(typeof {}); // object
        console.log(typeof undefined); // undefined
        console.log(typeof null); // object
        console.log(typeof NaN); // number 

        // instanceof 会返回true/false
        console.log([] instanceof Array)
        console.log(2 instanceof Number); // false
        console.log(true instanceof Boolean); // false
        console.log('str' instanceof String); // false
        console.log([] instanceof Array); // true
        console.log(function(){} instanceof Function); // true
        console.log({} instanceof Object); // true

        // typeof 会返回⼀个变量的基本类型， instanceof 返回的是⼀个布尔值
        // instanceof 只能正确判断引⽤数据类型，⽽不能判断基本数据类型。 instanceof 运算
// 符可以⽤来测试⼀个对象在其原型链中是否存在⼀个构造函数的 prototype 属性。
// ⽽ typeof 也存在弊端，它虽然可以判断基础数据类型（ null 除外），但是引⽤数据类型中，除了 function 类型以外，其他的也⽆法判断，这个时候就该 Object.prototype.toString

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
console.log((false).constructor === Boolean)


// Object.prototype.toString.call()
// Object.prototype.toString.call() 使⽤ Object 对象的原型⽅法 toString 来判断数据类型：

var a = Object.prototype.toString
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){}));
console.log(a.call({}));
console.log(a.call(undefined));
console.log(a.call(null));


let n1 = 0.1, n2 = 0.2
console.log(n1 + n2) // 0.30000000000000004
// 所以计算机计算0.1+0.2的时候，实际上是计算的两个数的⼆进
// 制的和。0.1的⼆进制是 0.0001100110011001100... （1100循环），0.2的⼆进制是：
// 0.00110011001100... （1100循环），这两个数的⼆进制都是⽆限循环的数。那JavaScript是如何
// 处理⽆限循环的⼆进制⼩数呢？

console.log((n1 + n2).toFixed(1)); // 0.3

// 原来NaN是(not a number)的缩写

console.log('==1', 1 == '1') // true
console.log('==2', true == '1') // true

// 使⽤双等号（==）进⾏相等判断时，如果两边的类型不⼀致，则会进⾏强制类型转化后再进⾏⽐
// 较。
// 使⽤三等号（===）进⾏相等判断时，如果两边的类型不⼀致时，不会做强制类型准换，直接返回
// false。

// 如何进行 隐式转换  ===> + - * /
console.log('*',1 * '23'); // 23
console.log('<','a' < 'b') // true


let generSymbol = Symbol();
let otherSymbol = Symbol();

console.log('generSymbol',generSymbol == otherSymbol); // false

let generSymbol2 = Symbol(2);
let otherSymbol2 = Symbol(2);
console.log('generSymbol',generSymbol2 == otherSymbol2); // false

// 关于类型转换，对象常见的两个方法是toString() 和 valueOf()。

// 函数表达方式
// 1、函数声明
function sum1 (num1, num2){
    return num1 + num2
}

// 2、函数表达式
let sum2 = function (num1,num2) {
    return num1 + num2
}
// 总结 函数表达式和函数声明的区别在于，表达式的是提前将函数的名字拎出来，函数声明则没有，按照传统的该怎样怎样

// 3、箭头函数--是对函数表达式的升级
let sum3 = (num1,num2)=>{
    return num1 + num2
}


const result = "10" - 5 + 2 + '4' -'8'
const result1 = "10" - 5
const result2 = "10" - 5 + 2
const result3 = "10" - 5 + 2 + '4'
const result4 = 7 + '4'
console.log('result',result) 
console.log('result1',result1)// 5 减法运算符 只有一种含义：数值相减
console.log('result2',result2)// 7
console.log('result3',result3)// '74' JavaScript 的规则是：如果 + 的任意一个操作数是字符串，那么整个表达式就会被当作字符串连接来处理
console.log('result4',result4)// '74'
</script>
</body>
</html>